/*
 * @(#)NewsServiceImpl.java 2011-11-08
 *
 * Copyright 2011 北龙中网（北京）科技有限责任公司. All rights reserved.
 */
package cn.shangjia.shop.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import cn.shangjia.common.dao.support.Page;
import cn.shangjia.common.domain.NewsComment;
import cn.shangjia.common.domain.NewsOnline;
import cn.shangjia.common.domain.validate.ValidateUtils;
import cn.shangjia.common.exceptions.Logger;
import cn.shangjia.common.util.StringUtils;
import cn.shangjia.common.webservice.ws.company.NewsWebService;
import cn.shangjia.shop.config.Constants;
import cn.shangjia.shop.config.ShopConfig;
import cn.shangjia.shop.dao.AbstractCacheDao.CacheType;
import cn.shangjia.shop.dao.NewsCommentDao;
import cn.shangjia.shop.dao.NewsOnlineDao;
import cn.shangjia.shop.log.ShopLoggerFactory;
import cn.shangjia.shop.service.NewsService;

/**
 * 服务实现.
 *
 * @author <a href="mailto:wangxin@knet.cn">wangxin</a>
 * @version 1.0, 2011-11-08 18:13:36
 * @since 1.0
 */
@Service
public class NewsServiceImpl implements NewsService {
	
	@Resource
	private NewsOnlineDao newsOnlineDao;
	
	@Resource
	private NewsWebService newsWebServiceClient;
	
	@Resource
	private NewsCommentDao newsCommentDao;
	
	@Resource
	private ShopConfig shopConfig;
	
//	private static final String COMMENT_LIST_CACHE_KEY = "N-C-LIST";
	private static final int visitSize = 100;
	private static final int replySize = 1000;
	
	/*评论列表默认缓存前2页*/
//	private static final int cachePageSize = 2;
	
	private static final Logger logger = ShopLoggerFactory.getLogger(NewsService.class); 

	
	/*
	 * (non-Javadoc)
	 * @see cn.shangjia.shop.service.NewsService#getNews(java.lang.String)
	 */
	@Override
	public NewsOnline getNews(final String id) {
		
		if (StringUtils.isEmpty(id))
			return null;
		
		NewsOnline news = newsOnlineDao.read(id);
		if (news == null)
			return null;
		
		addVisitNum(news); //更新浏览量
		
		return news;
	}
	
	/*
	 * (non-Javadoc)
	 * @see cn.shangjia.shop.service.NewsService#findNewsPage(java.lang.String, int, int)
	 */
	@Override
	public Page<NewsOnline> findNewsPage(String userId, int pageNo, int pageSize) {
		
		Page<NewsOnline> page = new Page<NewsOnline>();
		
		if (StringUtils.isEmpty(userId)) {
			return page;
		}
		
		page.setPageNo(pageNo);
		page.setPageSize(pageSize);
		
		Map<String, Object> parames = new HashMap<String, Object>();
		parames.put("userId", userId);
		
		page.setTotalCount(newsOnlineDao.totalCount(parames));
		
		return newsOnlineDao.selectListPage(page , parames);
		
	}

	/*
	 * (non-Javadoc)
	 * @see cn.shangjia.shop.service.NewsService#addComment(cn.shangjia.common.domain.NewsComment)
	 */
	@Override
	public void addComment(final NewsComment comment) {
		
		Assert.notNull(comment);
		
		//从缓存中获取该条要评论的数据
		final NewsOnline news = newsOnlineDao.read(comment.getNewsId());
		if (news == null) {
			//该数据 已经被删除 或者 锁定 或者 关闭 . 默认不再提供发评论
			return;
		}
		
		//验证参数
		Map<String, String> errors = ValidateUtils.validate(comment);
		if (!errors.isEmpty()) {
			return;
		}
		
		//创建一条评论 入库
		String id = newsCommentDao.create(comment);
		if (StringUtils.isEmpty(id) || id.equals("0")) {
			// 入库失败
			logger.error("发表评论失败, 参数 : ", comment);
			return ; 
		}
			
		addReplyNum(news); //增加回复数量
		
		//更新缓存 流程
		//获得 参数
		Map<String, Object> params = getParams(comment.getNewsId());
		
		//更新缓存中的 totalCount
		long totalCount = getCacheTotalCount(params);
		totalCount++;
		newsCommentDao.replace(getCacheCountKey(params), totalCount);
		
		//更新缓存中的 缓存页中的列表数据
		int size = /*评论每页的要显示的记录数*/shopConfig.getNewsCommentPagesize() * /*要缓存的页数*/shopConfig.getNewsCommentCachePageSize();
		Page<NewsComment> page = new Page<NewsComment>(size);
		List<NewsComment> list = getCacheList(page, params);
		if (list != null) {
			while (list.size() >= size) {
				list.remove(list.size() - 1);
			}
			list.add(0, comment);
			newsCommentDao.replace(getCahceListKey(page, params), list);
		}
		
	}

	
	@Override
	public Page<NewsComment> getCommentPage(String newsId, int pageNo, int pageSize) {
		
		//填充配置对象
		Page<NewsComment> page = new Page<NewsComment>();
		page.setAutoCount(false);
		page.setPageNo(pageNo);
		page.setPageSize(pageSize);
		long totalCount =  newsCommentDao.totalCount(getParams(newsId));
		page.setTotalCount(totalCount);
		
		//如果 要取的页面 大于缓存中存得数量 . 那么 直接查库返回
		if (pageSize > /*要缓存的页数*/shopConfig.getNewsCommentCachePageSize()) 
			return newsCommentDao.selectListPageNoCache(page, getParams(newsId));

		// 如果 在缓存范围内的流程
		int size = /*评论每页的要显示的记录数*/shopConfig.getNewsCommentPagesize() * /*要缓存的页数*/shopConfig.getNewsCommentCachePageSize();
		page.setPageNo(1);
		page.setPageSize(size);  //重置  直接取出 要缓存页数的数据量
		
		//获得缓存中的list
		List<NewsComment> cacheList = getCacheList(page, getParams(newsId));
		if (cacheList == null) {
			logger.error("[企业动态] - 操作缓存时 无法获取缓存的key, 已经停用缓存机制. 请迅速核查");
			return newsCommentDao.selectListPageNoCache(page, getParams(newsId)); 
		}
		
		//创建返回结果
		List<NewsComment> result = new ArrayList<NewsComment>(pageSize);

		//将 要查询页结果进行填充
		int i = (pageNo - 1) * pageSize;
		int j = i + pageSize;
		
		for (; i < j; i ++) 
			result.add(cacheList.get(i));
		
		page.setPageSize(pageSize); //将pageSize还原
		page.setPageNo(pageNo); //将pegeNo还原
		page.setResult(result); //替换单页结果
		
		//返回
		return page;
	}
	
	/**
	 *  获取缓存中的记录条数
	 * 
	 * @param parames
	 * @return
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	private long getCacheTotalCount(Map<String, Object> parames) {
		String key = getCacheCountKey(parames);
		if (key == null) {
			return 0;
		}
		Long count = (Long) newsCommentDao.get(key);
		if (count == null)
			return 0;
		return count.longValue();
	}
	
	/**
	 *  获取缓存中的列表
	 * 
	 * @param page
	 * @param parames
	 * @return
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	@SuppressWarnings("unchecked")
	private List<NewsComment> getCacheList(Page<NewsComment> page, Map<String, Object> parames) {
		String key = getCahceListKey(page, parames);
		if (key == null) {
			return null;
		}
		Collection<NewsComment> cacheResult = (Collection<NewsComment>) newsCommentDao.get(key); //从缓存拿出列表的值
		if (cacheResult == null) { //缓存有数据
			cacheResult = newsCommentDao.selectListPage(page, parames).getResult(); //拿出要缓存的数据 并放入缓存
		}
		return  new ArrayList<NewsComment>(cacheResult);
	}
	
	private String getCacheCountKey(Map<String, Object> parames) {
		String key = newsCommentDao.getKey(CacheType.CNT, parames); //拿到缓存COUNT的KEY
		return key;
	}
	private String getCahceListKey(Page<NewsComment> page, Map<String, Object> parames) {
		String key = newsCommentDao.getKey(CacheType.LIST, newsCommentDao.getPageParames(page, parames)); //拿到缓存列表的KEY
		return key;
	}
	private Map<String, Object> getParams(String newsId) {
		Map<String, Object> parames = new HashMap<String, Object>();
		parames.put("newsId", newsId);
		return parames;
	}
	
	/**
	 *  添加回复量 
	 * 
	 * @param news
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	private void addReplyNum(NewsOnline news) {
		
		final String id = news.getId();
		
		int replyNum = news.getReplyNum();
		replyNum++;
		news.setReplyNum(replyNum);
		int tmpReplyNum = news.getTmpReplyNum();
		tmpReplyNum++;
		if (tmpReplyNum >= replySize) {
			final int num = tmpReplyNum;
			tmpReplyNum = 0;
			Constants.webserviceExecutorService.execute(new Runnable() {
				@Override
				public void run() {
					newsWebServiceClient.addReplyNum(id, num);
				}
			});
		}
		news.setTmpReplyNum(tmpReplyNum);
		
		String key = newsOnlineDao.getKey(CacheType.OBJ, id);
		newsOnlineDao.replace(key, news);
	}
	
	/**
	 *  添加访问量
	 * 
	 * @param news
	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
	 */
	private void addVisitNum(NewsOnline news) {
		
		final String id = news.getId();
		
		int visitNum = news.getVisitNum();
		visitNum ++;
		news.setVisitNum(visitNum);
		
		int tmpVisitNum = news.getTmpVisitNum();
		tmpVisitNum ++;
		
		if (tmpVisitNum >= visitSize) {
			final int num = tmpVisitNum;
			tmpVisitNum = 0;
			Constants.webserviceExecutorService.execute(new Runnable() {
				@Override
				public void run() {
					newsWebServiceClient.addVisitNum(id, num);
				}
			});
		}
		
		news.setTmpVisitNum(tmpVisitNum);
		
		String key = newsOnlineDao.getKey(CacheType.OBJ, id);
		newsOnlineDao.replace(key, news);
	}
	
	

//	@Override
//	public List<NewsComment> getCommentListByNewsIdAsNew(String newsId, int num) {
//		
//		List<NewsComment> list = new ArrayList<NewsComment>();
//		if (StringUtils.isEmpty(newsId)) 
//			return list;
//		List<NewsComment> cacheList = getCacheCommentList();
//		for (NewsComment nc : cacheList) {
//			if (newsId.equals(nc.getNewsId()))
//				list.add(nc);
//			if (list.size() >= num)
//				return list;
//		}
//		int ts = num - list.size();
//		Page<NewsComment> page = new Page<NewsComment>();
//		Map<String, Object> parames = new HashMap<String, Object>();
//		page.setAutoCount(false);
//		page.setPageNo(1);
//		page.setPageSize(ts);
//		page.setTotalCount(totalCount)
//		newsCommentDao.selectListPageNoCache(page, parames);
//		return null;
//	}
	
//	/**
//	 *  添加评论
//	 * 
//	 * @param comment
//	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
//	 */
//	@Override
//	public void addComment(NewsComment comment) {
//		
//		Assert.notNull(comment);
//		
//		//从缓存中获取该条要评论的数据
//		NewsOnline news = newsOnlineDao.read(comment.getNewsId());
//		if (news == null) {
//			//该数据 已经被删除 或者 锁定 或者 关闭 . 默认不再提供发评论
//			return;
//		}
//		
//		addReplyNum(news); //增加回复数量
//		
//		//将回复放到缓存里
//		List<NewsComment> list = getCacheCommentList();
//		list.add(comment);
//		
//		//如果 缓存里的 回复数量大于 指定入库 数量 则开始入库
//		if (list.size() >= replySize) {
//			// 转换到临时文件中, 并且清空掉 缓存中的list;
//			final List<NewsComment> tmplist = list;
//			list = new ArrayList<NewsComment>();
//			
//			//开启 webservice通信 入库线程.
//			webserviceExecutorService.execute(new Runnable() {
//				@Override
//				public void run() {
//					try {
//						newsCommentWebServiceClient.addComments(tmplist);
//					} catch (Exception e) {
//						e.printStackTrace();
//					}
//				}
//			});
//		}
//		
//		//更新缓存中的评论列表
//		newsCommentDao.replace(COMMENT_LIST_CACHE_KEY, list);
//	}
	
//	/**
//	 *  从缓存中获取评论列表
//	 * 
//	 * @return
//	 * @author <a href="mailto:jinzhongze@knet.cn">jinzhongze</a>
//	 */
//	@SuppressWarnings("unchecked")
//	private List<NewsComment> getCacheCommentList() {
//		List<NewsComment> list = (List<NewsComment>) newsCommentDao.get(COMMENT_LIST_CACHE_KEY);
//		if (list == null) {
//			list = new ArrayList<NewsComment>();
//			newsCommentDao.add(COMMENT_LIST_CACHE_KEY, list);
//		}
//		return list;
//	}
	
}
